/*******************************************************************
 *
 *  ttapi.c
 *
 *    High-level interface implementation
 *
 *  Copyright 1996-1999 by
 *  David Turner, Robert Wilhelm, and Werner Lemberg.
 *
 *  This file is part of the FreeType project, and may only be used,
 *  modified, and distributed under the terms of the FreeType project
 *  license, LICENSE.TXT.  By continuing to use, modify, or distribute
 *  this file you indicate that you have read the license and
 *  understand and accept it fully.
 *
 *  Notes:
 *
 *    This file is used to implement most of the functions that are
 *    defined in the file "freetype.h". However, two functions are
 *    implemented elsewhere :
 *
 *     TT_MulDiv and TT_MulFix  are in ttcalc.h/ttcalc.c
 *
 ******************************************************************/

#include "ttconfig.h"

#include "freetype.h"
#include "ttengine.h"
#include "ttcalc.h"
#include "ttmemory.h"
#include "ttcache.h"
#include "ttfile.h"
#include "ttobjs.h"
#include "ttload.h"
#include "ttgload.h"
#include "ttraster.h"
#include "ttextend.h"

/* required by the tracing mode */
#undef  TT_COMPONENT
#define TT_COMPONENT  trace_api

#ifdef TT_STATIC_RASTER
#define RAS_OPS	/* void */
#define RAS_OP	/* void */
#else
#define RAS_OPS  ((TRaster_Instance*)_engine->raster_component),
#define RAS_OP   ((TRaster_Instance*)_engine->raster_component)
#endif							/* TT_STATIC_RASTER */

#define RENDER_Glyph( glyph, target ) \
          Render_Glyph( RAS_OPS  glyph, target )

#define RENDER_Gray_Glyph( glyph, target, palette ) \
          Render_Gray_Glyph( RAS_OPS  glyph, target, palette )

/*******************************************************************
 *
 *  Function    :  TT_FreeType_Version
 *
 *  Description :  Returns the major and minor version of the library.
 *
 *  Input  :  major, minor addresses
 *
 *  Output :  Error code.
 *
 *  MT-Note : YES!
 *
 ******************************************************************/

EXPORT_FUNC TT_Error TT_FreeType_Version(int *major, int *minor)
{
	if (!major || !minor)
		return TT_Err_Invalid_Argument;

	*major = TT_FREETYPE_MAJOR;
	*minor = TT_FREETYPE_MINOR;

	return TT_Err_Ok;
}

/*******************************************************************
 *
 *  Function    : TT_Init_FreeType
 *
 *  Description : The library's engine initializer.  This function
 *                must be called prior to any call.
 *
 *  Input  :  engine        pointer to a FreeType engine instance
 *
 *  Output :  Error code.
 *
 *  MT-Note : This function should be called each time you want
 *            to create a TT_Engine.  It is not necessarily thread
 *            safe depending on the implementations of ttmemory,
 *            ttfile and ttmutex, so take care.  Their default
 *            implementations are safe, however.
 *
 ******************************************************************/

EXPORT_FUNC TT_Error TT_Init_FreeType(TT_Engine * engine)
{
	PEngine_Instance _engine;

	TT_Error error;
	int n;

	/* first of all, initialize memory sub-system */
	error = TTMemory_Init();
	if (error)
		return error;

	/* Allocate engine instance */
	if (ALLOC(_engine, sizeof(TEngine_Instance)))
		return error;

#undef  TT_FAIL
#define TT_FAIL( x )  ( error = x (_engine) ) != TT_Err_Ok

	/* Initalize components */
	if (TT_FAIL(TTFile_Init) || TT_FAIL(TTCache_Init) ||
#ifdef TT_CONFIG_OPTION_EXTEND_ENGINE
		TT_FAIL(TTExtend_Init) ||
#endif
		TT_FAIL(TTObjs_Init) || TT_FAIL(TTRaster_Init))
		goto Fail;

#undef TT_FAIL

	/* set the gray palette defaults: 0 to 4 */
	for (n = 0; n < 5; n++)
		_engine->raster_palette[n] = (Byte) n;	/* Conversion ok, some warn */

	/* create the engine lock */
	MUTEX_Create(_engine->lock);

	HANDLE_Set(*engine, _engine);
	return TT_Err_Ok;

  Fail:
	TT_Done_FreeType(*engine);
	HANDLE_Set(*engine, NULL);
	return error;
}

/*******************************************************************
 *
 *  Function    : TT_Done_FreeType
 *
 *  Description : The library's engine finalizer.  This function
 *                will discard all active face and glyph objects
 *                from the heap.
 *
 *  Input  :  engine        FreeType engine instance
 *
 *  Output :  Error code.
 *
 *  MT-Note : Destroys an engine.  Not necessarily thread-safe
 *            depending on the implementations of ttmemory,
 *            ttfile and ttmutex.  The default implementations
 *            are safe, however.
 *
 ******************************************************************/

EXPORT_FUNC TT_Error TT_Done_FreeType(TT_Engine engine)
{
	PEngine_Instance _engine = HANDLE_Engine(engine);

	if (!_engine)
		return TT_Err_Ok;

	MUTEX_Destroy(_engine->lock);

	TTRaster_Done(_engine);
	TTObjs_Done(_engine);
#ifdef TT_CONFIG_OPTION_EXTEND_ENGINE
	TTExtend_Done(_engine);
#endif
	TTCache_Done(_engine);
	TTFile_Done(_engine);
	FREE(_engine);

	TTMemory_Done();

	return TT_Err_Ok;
}

#ifdef TT_CONFIG_OPTION_GRAY_SCALING

/*******************************************************************
 *
 *  Function    :  TT_Set_Raster_Gray_Palette
 *
 *  Description :  Sets the gray-levels palette used for font
 *                 smoothing.
 *
 *  Input  :  engine        FreeType engine instance
 *            palette       address of palette (a 5 byte array)
 *
 *  Output :  Invalid argument if 'palette' is NULL.
 *
 *  MT-Note:  NO!  Unprotected modification of an engine's palette.
 *
 ******************************************************************/

EXPORT_FUNC TT_Error TT_Set_Raster_Gray_Palette(TT_Engine engine, Byte * palette)
{
	int i;

	if (!palette)
		return TT_Err_Invalid_Argument;

	for (i = 0; i < 5; i++)
		HANDLE_Engine(engine)->raster_palette[i] = (Byte) palette[i];

	return TT_Err_Ok;
}

#endif							/* TT_CONFIG_OPTION_GRAY_SCALING */

/*******************************************************************
 *
 *  Function    :  TT_Open_Face
 *
 *  Description :  Creates a new face object from a given font file.
 *
 *  Input  :  engine        FreeType engine instance
 *            fontPathName  the font file's pathname
 *            face          adress of returned face handle
 *
 *  Output :  Error code.
 *
 *  Note :    The face handle is set to NULL in case of failure.
 *
 *  MT-Note : YES!
 *
 ******************************************************************/

EXPORT_FUNC TT_Error TT_Open_Face(TT_Engine engine, const TT_Text * fontPathName, TT_Face * face)
{
	PEngine_Instance _engine = HANDLE_Engine(engine);

	TFont_Input input;
	TT_Error error;
	TT_Stream stream;
	PFace _face;

	if (!_engine)
		return TT_Err_Invalid_Engine;

	/* open the file */
	error = TT_Open_Stream(fontPathName, &stream);
	if (error)
		return error;

	input.stream = stream;
	input.fontIndex = 0;
	input.engine = _engine;

	/* Create and load the new face object - this is thread-safe */
	error = CACHE_New(_engine->objs_face_cache, _face, &input);

	/* Set the handle */
	HANDLE_Set(*face, _face);

	if (error)
		goto Fail;

	return TT_Err_Ok;

  Fail:
	TT_Close_Stream(&stream);
	return error;
}

/*******************************************************************
 *
 *  Function    :  TT_Open_Collection
 *
 *  Description :  Creates a new face object from a given font file.
 *
 *  Input  :  engine                FreeType engine instance
 *            collectionPathName    the font file's pathname
 *            fontIndex             index of font in TrueType collection
 *            face                  adress of returned face handle
 *
 *  Output :  Error code.
 *
 *  Note :    The face handle is set to NULL in case of failure.
 *
 *  MT-Note : YES!
 *
 ******************************************************************/

EXPORT_FUNC TT_Error TT_Open_Collection(TT_Engine engine, const TT_Text * collectionPathName, TT_ULong fontIndex,
										TT_Face * face)
{
	PEngine_Instance _engine = HANDLE_Engine(engine);

	TFont_Input input;
	TT_Error error;
	TT_Stream stream;
	PFace _face;

	if (!_engine)
		return TT_Err_Invalid_Engine;

	/* open the file */
	error = TT_Open_Stream(collectionPathName, &stream);
	if (error)
		return error;

	input.stream = stream;
	input.fontIndex = fontIndex;
	input.engine = _engine;

	/* Create and load the new face object - this is thread-safe */
	error = CACHE_New(_engine->objs_face_cache, _face, &input);

	/* Set the handle */
	HANDLE_Set(*face, _face);

	if (error)
		goto Fail;

	return TT_Err_Ok;

  Fail:
	TT_Close_Stream(&stream);

	return error;
}

/*******************************************************************
 *
 *  Function    :  TT_Get_Face_Properties
 *
 *  Description :  Returns face properties.
 *
 *  Input  :  face          the face handle
 *            properties    address of target properties record
 *
 *  Output :  Error code.
 *
 *  Note :    Currently, max_Faces is always set to 0.
 *
 *  MT-Note : YES!  Reads only permanent data.
 *
 ******************************************************************/

EXPORT_FUNC TT_Error TT_Get_Face_Properties(TT_Face face, TT_Face_Properties * properties)
{
	PFace _face = HANDLE_Face(face);

	if (!_face)
		return TT_Err_Invalid_Face_Handle;

	properties->num_Glyphs = _face->numGlyphs;
	properties->max_Points = _face->maxPoints;
	properties->max_Contours = _face->maxContours;
	properties->num_CharMaps = _face->numCMaps;
	properties->num_Names = _face->nameTable.numNameRecords;

	if (_face->ttcHeader.DirCount == 0)
		properties->num_Faces = 1;
	else
		properties->num_Faces = _face->ttcHeader.DirCount;

	properties->header = &_face->fontHeader;
	properties->horizontal = &_face->horizontalHeader;

	if (_face->verticalInfo)
		properties->vertical = &_face->verticalHeader;
	else
		properties->vertical = NULL;

	properties->os2 = &_face->os2;
	properties->postscript = &_face->postscript;
	properties->hdmx = &_face->hdmx;

	return TT_Err_Ok;
}

/*******************************************************************
 *
 *  Function    :  TT_Set_Face_Pointer
 *
 *  Description :  Each face object has one pointer, which use is
 *                 reserved to client applications.  The TrueType
 *                 engine never accesses or uses this field.
 *
 *                 This function is used to set the pointer.
 *
 *  Input  :  face    the given face handle
 *            data    the generic pointer value
 *
 *  Output :  Error code.
 *
 *  MT-Note : NO!  But this function is reserved to "enlightened"
 *            developers, so it shouldn't be a problem.
 *
 ******************************************************************/

EXPORT_FUNC TT_Error TT_Set_Face_Pointer(TT_Face face, void *data)
{
	PFace faze = HANDLE_Face(face);

	if (!faze)
		return TT_Err_Invalid_Face_Handle;
	else
		faze->generic = data;

	return TT_Err_Ok;
}

/*******************************************************************
 *
 *  Function    :  TT_Get_Face_Pointer
 *
 *  Description :  Each face object has one pointer, which use is
 *                 reserved to client applications.  The TrueType
 *                 engine never access or use this field.
 *
 *                 This function is used to read the pointer.
 *
 *  Input  :  face    the given face handle
 *            data    the generic pointer value
 *
 *  Output :  Error code.
 *
 *  MT-Note : NO!  But this function is reserved to "enlightened"
 *            developers, so it shouldn't be a problem.
 *
 ******************************************************************/

EXPORT_FUNC void *TT_Get_Face_Pointer(TT_Face face)
{
	PFace faze = HANDLE_Face(face);

	if (!faze)
		return NULL;
	else
		return faze->generic;
}

/*******************************************************************
 *
 *  Function    :  TT_Get_Face_Metrics
 *
 *  Description :  This function returns the original horizontal AND
 *                 vertical metrics as found in the "hmtx" and "vmtx"
 *                 tables.  These are the glyphs' left-side-bearings
 *                 and advance widths (horizontal), as well as top
 *                 side bearings and advance heights (vertical).
 *
 *                 All are expressed in FONT UNITS, a.k.a. EM
 *                 units.
 *
 *  Input  :     face  The given face handle.
 *              first  Index of first glyph in table.
 *               last  Index of last glyph in table.
 *
 *       leftBearings  A pointer to an array of TT_Shorts where the
 *                     left side bearings for the glyphs 'first'
 *                     to 'last' will be returned.  If these metrics
 *                     don't interest you, simply set it to NULL.
 *
 *             widths  A pointer to an array of TT_UShorts
 *                     where the advance widths for the glyphs
 *                     'first' to 'last' will be returned.  If these
 *                     metrics don't interest you, simply set it
 *                     to NULL.
 *
 *        topBearings  A pointer to an array of TT_Shorts where the
 *                     top side bearings for the glyphs 'first'
 *                     to 'last' will be returned.  If these metrics
 *                     don't interest you, simply set it to NULL.
 *
 *            heights  A pointer to an array of TT_UShorts
 *                     where the advance heights for the glyphs
 *                     'first' to 'last' will be returned.  If these
 *                     metrics don't interest you, simply set it
 *                     to NULL.
 *
 *  Output :  Error code.
 *
 *  IMPORTANT NOTE :
 *
 *  As vertical metrics are optional in a TrueType font, this
 *  function will return an error ( TT_Err_No_Vertical_Data )
 *  whenever this function is called on such a face with non-NULL
 *  'topBearings' or 'heights' arguments.
 *
 *  When a font has no vertical data, the 'vertical' field in its
 *  properties structure is set to NULL.
 *
 *  MT-Note : YES!  Reads only permanent data.
 *
 ******************************************************************/

EXPORT_FUNC TT_Error TT_Get_Face_Metrics(TT_Face face, TT_UShort firstGlyph, TT_UShort lastGlyph,
										 TT_Short * leftBearings, TT_UShort * widths, TT_Short * topBearings,
										 TT_UShort * heights)
{
	PFace _face = HANDLE_Face(face);
	UShort num;

	if (!_face)
		return TT_Err_Invalid_Face_Handle;

	/* Check the glyph range */
	if (lastGlyph >= _face->numGlyphs || firstGlyph > lastGlyph)
		return TT_Err_Invalid_Argument;

	num = lastGlyph - firstGlyph;	/* number of elements-1 in each array */

	/* store the left side bearings and advance widths first */
	{
		UShort n;
		Short left_bearing;
		UShort advance_width;

		for (n = 0; n <= num; n++) {
			TT_Get_Metrics(&_face->horizontalHeader, firstGlyph + n, &left_bearing, &advance_width);

			if (leftBearings)
				leftBearings[n] = left_bearing;
			if (widths)
				widths[n] = advance_width;
		}
	}

	/* check for vertical data if topBearings or heights is non-NULL */
	if (!topBearings && !heights)
		return TT_Err_Ok;

	if (!_face->verticalInfo)
		return TT_Err_No_Vertical_Data;

	/* store the top side bearings */
	{
		UShort n;
		Short top_bearing;
		UShort advance_height;

		for (n = 0; n <= num; n++) {
			TT_Get_Metrics((TT_Horizontal_Header *) & _face->verticalHeader, firstGlyph + n, &top_bearing,
						   &advance_height);

			if (topBearings)
				topBearings[n] = top_bearing;
			if (heights)
				heights[n] = advance_height;
		}
	}

	return TT_Err_Ok;
}

/*******************************************************************
 *
 *  Function    :  TT_Flush_Face
 *
 *  Description :  This function is used to close an active face's
 *                 file handle or descriptor.  This is useful to save
 *                 system resources, if your application uses tons
 *                 of fonts.
 *
 *  Input  :  face    the given face handle
 *
 *  Output :  Error code.
 *
 *  MT-Note : YES!  (If ttfile is.)
 *
 ******************************************************************/

EXPORT_FUNC TT_Error TT_Flush_Face(TT_Face face)
{
	PFace faze = HANDLE_Face(face);

	if (!faze)
		return TT_Err_Invalid_Face_Handle;
	else
		return TT_Flush_Stream(&faze->stream);
}

/*******************************************************************
 *
 *  Function    :  TT_Close_Face
 *
 *  Description :  Closes an opened face object.  This function
 *                 will destroy all objects associated to the
 *                 face, except the glyphs.
 *
 *  Input  :  face    the given face handle
 *
 *  Output :  Error code.
 *
 *  NOTE   :  The handle is set to NULL on exit.
 *
 *  MT-Note : YES!
 *
 ******************************************************************/

EXPORT_FUNC TT_Error TT_Close_Face(TT_Face face)
{
	PFace _face = HANDLE_Face(face);

	if (!_face)
		return TT_Err_Invalid_Face_Handle;

	TT_Close_Stream(&_face->stream);

	/* delete the face object -- this is thread-safe */
	return CACHE_Done(_face->engine->objs_face_cache, _face);
}

/*******************************************************************
 *
 *  Function    :  TT_New_Instance
 *
 *  Description :  Creates a new instance from a given face.
 *
 *  Input  :  face        parent face handle
 *            instance    address of instance handle
 *
 *  Output :  Error code.
 *
 *  Note   :  The handle is set to NULL in case of failure.
 *
 *  MT-Note : YES!
 *
 ******************************************************************/

EXPORT_FUNC TT_Error TT_New_Instance(TT_Face face, TT_Instance * instance)
{
	TT_Error error;
	PFace _face = HANDLE_Face(face);
	PInstance _ins;

	if (!_face)
		return TT_Err_Invalid_Face_Handle;

	/* get a new instance from the face's cache -- this is thread-safe */
	error = CACHE_New(&_face->instances, _ins, _face);

	HANDLE_Set(*instance, _ins);

	if (!error) {
		error = Instance_Init(_ins);
		if (error) {
			HANDLE_Set(*instance, NULL);
			CACHE_Done(&_face->instances, _ins);
		}
	}

	return error;
}

/*******************************************************************
 *
 *  Function    :  TT_Set_Instance_Resolutions
 *
 *  Description :  Resets an instance to a new device resolution.
 *
 *  Input  :  instance      the instance handle
 *            xResolution   new horizontal device resolution in dpi
 *            yResolution   new vertical device resolution in dpi
 *
 *  Output :  Error code.
 *
 *  Note :    There is no check for overflow; with other words,
 *            the product of glyph dimensions times the device
 *            resolutions must have reasonable values.
 *
 *  MT-Note : You should set the charsize or pixel size immediately
 *            after this call in multi-threaded programs.  This will
 *            force the instance data to be resetted.  Otherwise, you
 *            may encounter corruption when loading two glyphs from
 *            the same instance concurrently!
 *
 *            Happily, 99.99% will do just that :-)
 *
 ******************************************************************/

EXPORT_FUNC TT_Error TT_Set_Instance_Resolutions(TT_Instance instance, TT_UShort xResolution, TT_UShort yResolution)
{
	PInstance ins = HANDLE_Instance(instance);

	if (!ins)
		return TT_Err_Invalid_Instance_Handle;

	ins->metrics.x_resolution = xResolution;
	ins->metrics.y_resolution = yResolution;
	ins->valid = FALSE;

	/* In the case of a thread-safe implementation, we immediately    */
	/* call Instance_Reset in order to change the instance's variable */

	/* In the case of a non-threaded build, we simply set the 'valid' */
	/* flag to FALSE, which will force the instance's resetting at    */
	/* the next glyph loading                                         */

	return TT_Err_Ok;
}

/*******************************************************************
 *
 *  Function    :  TT_Set_Instance_CharSizes
 *
 *  Description :  Resets an instance to new point size.
 *
 *  Input  :  instance      the instance handle
 *            charWidth     the new width in 26.6 char points
 *            charHeight    the new height in 26.6 char points
 *
 *  Output :  Error code.
 *
 *  Note :    There is no check for overflow; with other words,
 *            the product of glyph dimensions times the device
 *            resolution must have reasonable values.
 *
 *  MT-Note : NO!  This should be called only when setting/resetting
 *            instances, so there is no need to protect.
 *
 ******************************************************************/

EXPORT_FUNC TT_Error TT_Set_Instance_CharSizes(TT_Instance instance, TT_F26Dot6 charWidth, TT_F26Dot6 charHeight)
{
	PInstance ins = HANDLE_Instance(instance);

	if (!ins)
		return TT_Err_Invalid_Instance_Handle;

	if (charWidth < 1 * 64)
		charWidth = 1 * 64;

	if (charHeight < 1 * 64)
		charHeight = 1 * 64;

	ins->metrics.x_scale1 = (charWidth * ins->metrics.x_resolution) / 72;
	ins->metrics.x_scale2 = ins->owner->fontHeader.Units_Per_EM;

	ins->metrics.y_scale1 = (charHeight * ins->metrics.y_resolution) / 72;
	ins->metrics.y_scale2 = ins->owner->fontHeader.Units_Per_EM;

	if (ins->owner->fontHeader.Flags & 8) {
		ins->metrics.x_scale1 = (ins->metrics.x_scale1 + 32) & -64;
		ins->metrics.y_scale1 = (ins->metrics.y_scale1 + 32) & -64;
	}

	ins->metrics.x_ppem = ins->metrics.x_scale1 / 64;
	ins->metrics.y_ppem = ins->metrics.y_scale1 / 64;

	if (charWidth > charHeight)
		ins->metrics.pointSize = charWidth;
	else
		ins->metrics.pointSize = charHeight;

	ins->valid = FALSE;

	return Instance_Reset(ins);
}

/*******************************************************************
 *
 *  Function    :  TT_Set_Instance_CharSize
 *
 *  Description :  Resets an instance to new point size.
 *
 *  Input  :  instance      the instance handle
 *            charSize      the new character size in 26.6 char points
 *
 *  Output :  Error code.
 *
 *  Note :    There is no check for overflow; with other words,
 *            the product of glyph dimensions times the device
 *            resolution must have reasonable values.
 *
 *  MT-Note : NO!  This should be called only when setting/resetting
 *            instances, so there is no need to protect.
 *
 ******************************************************************/

EXPORT_FUNC TT_Error TT_Set_Instance_CharSize(TT_Instance instance, TT_F26Dot6 charSize)
{
	return TT_Set_Instance_CharSizes(instance, charSize, charSize);
}

/*******************************************************************
 *
 *  Function    :  TT_Set_Instance_PixelSizes
 *
 *  Description :  Resets an instance to new pixel sizes
 *
 *  Input  :  instance      the instance handle
 *            pixelWidth    the new width in pixels
 *            pixelHeight   the new height in pixels
 *
 *  Output :  Error code.
 *
 *  Note :    There is no check for overflow; with other words,
 *            the product of glyph dimensions times the device
 *            resolution must have reasonable values.
 *
 *  MT-Note : NO!  This should be called only when setting/resetting
 *            instances, so there is no need to protect.
 *
 ******************************************************************/

EXPORT_FUNC TT_Error TT_Set_Instance_PixelSizes(TT_Instance instance, TT_UShort pixelWidth, TT_UShort pixelHeight,
												TT_F26Dot6 pointSize)
{
	PInstance ins = HANDLE_Instance(instance);

	if (!ins)
		return TT_Err_Invalid_Instance_Handle;

	if (pixelWidth < 1)
		pixelWidth = 1;
	if (pixelHeight < 1)
		pixelHeight = 1;

	ins->metrics.x_ppem = pixelWidth;
	ins->metrics.y_ppem = pixelHeight;
	ins->metrics.pointSize = pointSize;

	ins->metrics.x_scale1 = ins->metrics.x_ppem * 64L;
	ins->metrics.x_scale2 = ins->owner->fontHeader.Units_Per_EM;
	ins->metrics.y_scale1 = ins->metrics.y_ppem * 64L;
	ins->metrics.y_scale2 = ins->owner->fontHeader.Units_Per_EM;

	ins->valid = FALSE;

	return Instance_Reset(ins);
}

/*******************************************************************
 *
 *  Function    :  TT_Set_Instance_Transform_Flags
 *
 *  Description :  Informs the interpreter about the transformations
 *                 that will be applied to the rendered glyphs.
 *
 *  Input  :  instance      the instance handle
 *            rotated       set to TRUE if the glyph are rotated
 *            stretched     set to TRUE if the glyph are stretched
 *
 *  Output :  Error code.
 *
 *  Note :    This function is deprecated!  It's much better to
 *            control hinting manually when calling TT_Load_Glyph
 *            than relying on the font programs...
 *
 *            Never use it, unless calling for trouble ;-)
 *
 *  MT-Note : NO!  This should be called only when setting/resetting
 *            instances, so there is no need to protect.
 *
 ******************************************************************/

EXPORT_FUNC TT_Error TT_Set_Instance_Transform_Flags(TT_Instance instance, TT_Bool rotated, TT_Bool stretched)
{
	PInstance ins = HANDLE_Instance(instance);

	if (!ins)
		return TT_Err_Invalid_Instance_Handle;

	ins->metrics.rotated = rotated;
	ins->metrics.stretched = stretched;
	ins->valid = FALSE;

	return TT_Err_Ok;
}

/*******************************************************************
 *
 *  Function    :  TT_Get_Instance_Metrics
 *
 *  Description :  Returns instance metrics.
 *
 *  Input  :  instance      the instance handle
 *            metrics       address of target instance metrics record
 *
 *  Output :  Error code.
 *
 *  MT-Note : YES!  Reads only semi-permanent data.
 *
 ******************************************************************/

EXPORT_FUNC TT_Error TT_Get_Instance_Metrics(TT_Instance instance, TT_Instance_Metrics * metrics)
{
	PInstance ins = HANDLE_Instance(instance);

	if (!ins)
		return TT_Err_Invalid_Instance_Handle;

	if (!ins->valid)
		Instance_Reset(ins);

	metrics->pointSize = ins->metrics.pointSize;

	metrics->x_scale = TT_MulDiv(0x10000, ins->metrics.x_scale1, ins->metrics.x_scale2);

	metrics->y_scale = TT_MulDiv(0x10000, ins->metrics.y_scale1, ins->metrics.y_scale2);

	metrics->x_resolution = ins->metrics.x_resolution;
	metrics->y_resolution = ins->metrics.y_resolution;
	metrics->x_ppem = ins->metrics.x_ppem;
	metrics->y_ppem = ins->metrics.y_ppem;

	return TT_Err_Ok;
}

/*******************************************************************
 *
 *  Function    :  TT_Set_Instance_Pointer
 *
 *  Description :  Each instance has one pointer, which use is
 *                 reserved to client applications.  The TrueType
 *                 engine never accesses or uses this field.
 *
 *                 This function is used to set the pointer.
 *
 *  Input  :  face    the given face handle
 *            data    the generic pointer value
 *
 *  Output :  Error code.
 *
 *  MT-Note : NO!
 *
 ******************************************************************/

EXPORT_FUNC TT_Error TT_Set_Instance_Pointer(TT_Instance instance, void *data)
{
	PInstance ins = HANDLE_Instance(instance);

	if (!ins)
		return TT_Err_Invalid_Instance_Handle;
	else
		ins->generic = data;

	return TT_Err_Ok;
}

/*******************************************************************
 *
 *  Function    :  TT_Get_Instance_Pointer
 *
 *  Description :  Each instance has one pointer, which use is
 *                 reserved to client applications.  The TrueType
 *                 engine never accesses or uses this field.
 *
 *                 This function is used to read the pointer.
 *
 *  Input  :  face    the given face handle
 *            data    the generic pointer value
 *
 *  Output :  Error code.
 *
 *  MT-Safe : NO!
 *
 ******************************************************************/

EXPORT_FUNC void *TT_Get_Instance_Pointer(TT_Instance instance)
{
	PInstance ins = HANDLE_Instance(instance);

	if (!ins)
		return NULL;
	else
		return ins->generic;
}

/*******************************************************************
 *
 *  Function    :  TT_Done_Instance
 *
 *  Description :  Closes a given instance.
 *
 *  Input  :  instance      address of instance handle
 *
 *  Output :  Error code.
 *
 *  MT-Safe : YES!
 *
 ******************************************************************/

EXPORT_FUNC TT_Error TT_Done_Instance(TT_Instance instance)
{
	PInstance ins = HANDLE_Instance(instance);

	if (!ins)
		return TT_Err_Invalid_Instance_Handle;

	/* delete the instance -- this is thread-safe */
	return CACHE_Done(&ins->owner->instances, ins);
}

/*******************************************************************
 *
 *  Function    :  TT_New_Glyph
 *
 *  Description :  Creates a new glyph object related to a given
 *                 face.
 *
 *  Input  :  face       the face handle
 *            glyph      address of target glyph handle
 *
 *  Output :  Error code.
 *
 *  MT-Safe : YES!
 *
 ******************************************************************/

EXPORT_FUNC TT_Error TT_New_Glyph(TT_Face face, TT_Glyph * glyph)
{
	TT_Error error;
	PFace _face = HANDLE_Face(face);
	PGlyph _glyph;

	if (!_face)
		return TT_Err_Invalid_Face_Handle;

	/* get a new glyph from the face's cache -- this is thread-safe */
	error = CACHE_New(&_face->glyphs, _glyph, _face);

	HANDLE_Set(*glyph, _glyph);

	return error;
}

/*******************************************************************
 *
 *  Function    :  TT_Done_Glyph
 *
 *  Description :  Destroys a given glyph object.
 *
 *  Input  :  glyph  the glyph handle
 *
 *  Output :  Error code.
 *
 *  MT-Safe : YES!
 *
 ******************************************************************/

EXPORT_FUNC TT_Error TT_Done_Glyph(TT_Glyph glyph)
{
	PGlyph _glyph = HANDLE_Glyph(glyph);

	if (!_glyph)
		return TT_Err_Invalid_Glyph_Handle;

	/* delete the engine -- this is thread-safe */
	return CACHE_Done(&_glyph->face->glyphs, _glyph);
}

/*******************************************************************
 *
 *  Function    :  TT_Load_Glyph
 *
 *  Description :  Loads a glyph.
 *
 *  Input  :  instance      the instance handle
 *            glyph         the glyph handle
 *            glyphIndex    the glyph index
 *            loadFlags     flags controlling how to load the glyph
 *                          (none, scaled, hinted, both)
 *
 *  Output :  Error code.
 *
 *  MT-Safe : YES!
 *
 ******************************************************************/

EXPORT_FUNC TT_Error TT_Load_Glyph(TT_Instance instance, TT_Glyph glyph, TT_UShort glyphIndex, TT_UShort loadFlags)
{
	PInstance _ins;
	PGlyph _glyph;
	TT_Error error;

	_ins = HANDLE_Instance(instance);

	if (!_ins)
		loadFlags &= ~(TTLOAD_SCALE_GLYPH | TTLOAD_HINT_GLYPH);

	if ((loadFlags & TTLOAD_SCALE_GLYPH) == 0)
		_ins = 0;

	_glyph = HANDLE_Glyph(glyph);
	if (!_glyph)
		return TT_Err_Invalid_Glyph_Handle;

	if (_ins) {
		if (_ins->owner != _glyph->face)
			return TT_Err_Invalid_Face_Handle;

		if (!_ins->valid) {
			/* This code can only be called in non thread-safe builds */
			error = Instance_Reset(_ins);
			if (error)
				return error;
		}
	}

	return Load_TrueType_Glyph(_ins, _glyph, glyphIndex, loadFlags);
}

/*******************************************************************
 *
 *  Function    :  TT_Get_Glyph_Outline
 *
 *  Description :  Returns the glyph's outline data.
 *
 *  Input  :  glyph     the glyph handle
 *            outline   address where the glyph outline will be returned
 *
 *  Output :  Error code.
 *
 *  MT-Safe : YES!  Reads only semi-permanent data.
 *
 ******************************************************************/

EXPORT_FUNC TT_Error TT_Get_Glyph_Outline(TT_Glyph glyph, TT_Outline * outline)
{
	PGlyph _glyph = HANDLE_Glyph(glyph);

	if (!_glyph)
		return TT_Err_Invalid_Glyph_Handle;

	*outline = _glyph->outline;
	outline->owner = FALSE;

	return TT_Err_Ok;
}

/*******************************************************************
 *
 *  Function    :  TT_Get_Glyph_Metrics
 *
 *  Description :  Extracts the glyph's horizontal metrics information.
 *
 *  Input  :  glyph       glyph object handle
 *            metrics     address where metrics will be returned
 *
 *  Output :  Error code.
 *
 *  MT-Safe : NO!  Glyph containers can't be shared.
 *
 ******************************************************************/

EXPORT_FUNC TT_Error TT_Get_Glyph_Metrics(TT_Glyph glyph, TT_Glyph_Metrics * metrics)
{
	PGlyph _glyph = HANDLE_Glyph(glyph);

	if (!_glyph)
		return TT_Err_Invalid_Glyph_Handle;

	metrics->bbox = _glyph->metrics.bbox;
	metrics->bearingX = _glyph->metrics.horiBearingX;
	metrics->bearingY = _glyph->metrics.horiBearingY;
	metrics->advance = _glyph->metrics.horiAdvance;

	return TT_Err_Ok;
}

/*******************************************************************
 *
 *  Function    :  TT_Get_Glyph_Big_Metrics
 *
 *  Description :  Extracts the glyph's big metrics information.
 *
 *  Input  :  glyph       glyph object handle
 *            metrics     address where big metrics will be returned
 *
 *  Output :  Error code.
 *
 *  MT-Safe : NO!  Glyph containers can't be shared.
 *
 ******************************************************************/

EXPORT_FUNC TT_Error TT_Get_Glyph_Big_Metrics(TT_Glyph glyph, TT_Big_Glyph_Metrics * metrics)
{
	PGlyph _glyph = HANDLE_Glyph(glyph);

	if (!_glyph)
		return TT_Err_Invalid_Glyph_Handle;

	*metrics = _glyph->metrics;

	return TT_Err_Ok;
}

/*******************************************************************
 *
 *  Function    :  TT_Get_Glyph_Bitmap
 *
 *  Description :  Produces a bitmap from a glyph outline.
 *
 *  Input  :  glyph      the glyph container's handle
 *            map        target pixmap description block
 *            xOffset    x offset in fractional pixels (26.6 format)
 *            yOffset    y offset in fractional pixels (26.6 format)
 *
 *  Output :  Error code.
 *
 *  Note : Only use integer pixel offsets if you want to preserve
 *         the fine hints applied to the outline.  This means that
 *         xOffset and yOffset must be multiples of 64!
 *
 *  MT-Safe : NO!  Glyph containers can't be shared.
 *
 ******************************************************************/

EXPORT_FUNC TT_Error TT_Get_Glyph_Bitmap(TT_Glyph glyph, TT_Raster_Map * map, TT_F26Dot6 xOffset, TT_F26Dot6 yOffset)
{
	PEngine_Instance _engine;
	TT_Engine engine;
	TT_Error error;
	PGlyph _glyph = HANDLE_Glyph(glyph);

	TT_Outline outline;

	if (!_glyph)
		return TT_Err_Invalid_Glyph_Handle;

	_engine = _glyph->face->engine;
	HANDLE_Set(engine, _engine);

	outline = _glyph->outline;
	/* XXX : For now, use only dropout mode 2    */
	/* outline.dropout_mode = _glyph->scan_type; */
	outline.dropout_mode = 2;

	TT_Translate_Outline(&outline, xOffset, yOffset);
	error = TT_Get_Outline_Bitmap(engine, &outline, map);
	TT_Translate_Outline(&outline, -xOffset, -yOffset);

	return error;
}

#ifdef TT_CONFIG_OPTION_GRAY_SCALING

/*******************************************************************
 *
 *  Function    :  TT_Get_Glyph_Pixmap
 *
 *  Description :  Produces a grayscaled pixmap from a glyph
 *                 outline.
 *
 *  Input  :  glyph      the glyph container's handle
 *            map        target pixmap description block
 *            xOffset    x offset in fractional pixels (26.6 format)
 *            yOffset    y offset in fractional pixels (26.6 format)
 *
 *  Output :  Error code.
 *
 *  Note : Only use integer pixel offsets to preserve the fine
 *         hinting of the glyph and the 'correct' anti-aliasing
 *         (where vertical and horizontal stems aren't grayed).
 *         This means that xOffset and yOffset must be multiples
 *         of 64!
 *
 *         You can experiment with offsets of +32 to get 'blurred'
 *         versions of the glyphs (a nice effect at large sizes that
 *         some graphic designers may appreciate :)
 *
 *  MT-Safe : NO!  Glyph containers can't be shared.
 *
 ******************************************************************/

EXPORT_FUNC TT_Error TT_Get_Glyph_Pixmap(TT_Glyph glyph, TT_Raster_Map * map, TT_F26Dot6 xOffset, TT_F26Dot6 yOffset)
{
	PEngine_Instance _engine;
	TT_Engine engine;
	TT_Error error;
	PGlyph _glyph = HANDLE_Glyph(glyph);

	TT_Outline outline;

	if (!_glyph)
		return TT_Err_Invalid_Glyph_Handle;

	_engine = _glyph->face->engine;
	HANDLE_Set(engine, _engine);

	outline = _glyph->outline;
	/* XXX : For now, use only dropout mode 2    */
	/* outline.dropout_mode = _glyph->scan_type; */
	outline.dropout_mode = 2;

	TT_Translate_Outline(&outline, xOffset, yOffset);
	error = TT_Get_Outline_Pixmap(engine, &outline, map);
	TT_Translate_Outline(&outline, -xOffset, -yOffset);

	return error;
}

#endif							/* TT_CONFIG_OPTION_GRAY_SCALING */

static const TT_Outline null_outline = { 0, 0, NULL, NULL, NULL, 0, 0, 0, 0 };

/*******************************************************************
 *
 *  Function    :  TT_New_Outline
 *
 *  Description :  Creates a new TrueType outline, reserving
 *                 array space for a given number of points and
 *                 contours.
 *
 *  Input  :  numPoints         number of points
 *            numContours       number of contours
 *            outline           address of target outline structure
 *
 *  Output :  Error code
 *
 *  MT-Safe : YES!
 *
 ******************************************************************/

EXPORT_FUNC TT_Error TT_New_Outline(TT_UShort numPoints, TT_Short numContours, TT_Outline * outline)
{
	TT_Error error;

	if (!outline)
		return TT_Err_Invalid_Argument;

	*outline = null_outline;

	if (ALLOC(outline->points, numPoints * 2 * sizeof(TT_F26Dot6)) || ALLOC(outline->flags, numPoints * sizeof(Byte))
		|| ALLOC(outline->contours, numContours * sizeof(UShort)))
		goto Fail;

	outline->n_points = numPoints;
	outline->n_contours = numContours;
	outline->owner = TRUE;
	return TT_Err_Ok;

  Fail:
	outline->owner = TRUE;
	TT_Done_Outline(outline);
	return error;
}

/*******************************************************************
 *
 *  Function    :  TT_Done_Outline
 *
 *  Description :  Deletes an outline created through TT_New_Outline().
 *                 Calling this function for outlines returned
 *                 by TT_Get_Glyph_Outline() yields an error.
 *
 *  Input  :  outline        address of outline
 *
 *  Output :  Error code.
 *
 *  MT-Safe : YES!
 *
 ******************************************************************/

EXPORT_FUNC TT_Error TT_Done_Outline(TT_Outline * outline)
{
	if (outline) {
		if (outline->owner) {
			FREE(outline->points);
			FREE(outline->flags);
			FREE(outline->contours);
		}
		*outline = null_outline;
		return TT_Err_Ok;
	} else
		return TT_Err_Invalid_Argument;
}

/*******************************************************************
 *
 *  Function    :  TT_Get_Outline_Bitmap
 *
 *  Description :  Render a TrueType outline into a bitmap.
 *                 Note that the bitmap must be created by the caller.
 *
 *  Input  :  outline        the outline to render
 *            map            the target bitmap
 *
 *  Output :  Error code.
 *
 *  MT-Safe : YES!
 *
 ******************************************************************/

EXPORT_FUNC TT_Error TT_Get_Outline_Bitmap(TT_Engine engine, TT_Outline * outline, TT_Raster_Map * map)
{
	PEngine_Instance _engine = HANDLE_Engine(engine);
	TT_Error error;

	if (!_engine)
		return TT_Err_Invalid_Engine;

	if (!outline || !map)
		return TT_Err_Invalid_Argument;

	MUTEX_Lock(_engine->raster_lock);
	error = RENDER_Glyph(outline, map);
	MUTEX_Release(_engine->raster_lock);

	return error;
}

#ifdef TT_CONFIG_OPTION_GRAY_SCALING

/*******************************************************************
 *
 *  Function    :  TT_Get_Outline_Pixmap
 *
 *  Description :  Render a TrueType outline into a pixmap.
 *                 Note that the pixmap must be created by the caller.
 *
 *  Input  :  outline       the outline to render
 *            map           the target bitmap
 *
 *  Output :  Error code
 *
 *  MT-Safe : YES!
 *
 ******************************************************************/

EXPORT_FUNC TT_Error TT_Get_Outline_Pixmap(TT_Engine engine, TT_Outline * outline, TT_Raster_Map * map)
{
	PEngine_Instance _engine = HANDLE_Engine(engine);
	TT_Error error;

	if (!_engine)
		return TT_Err_Invalid_Engine;

	if (!outline || !map)
		return TT_Err_Invalid_Argument;

	MUTEX_Lock(_engine->raster_lock);
	error = RENDER_Gray_Glyph(outline, map, _engine->raster_palette);
	MUTEX_Release(_engine->raster_lock);
	return error;
}

#endif							/* TT_CONFIG_OPTION_GRAY_SCALING */

/*******************************************************************
 *
 *  Function    :  TT_Copy_Outline
 *
 *  Description :  Copy an outline into another.  The source and
 *                 target outlines must have the same points and
 *                 contours numbers.
 *
 *  Input  :  source         address of source outline
 *            target         address of target outline
 *
 *  Output :  Error code
 *
 *  Note :    This function doesn't touch the target outline's 'owner'
 *            field.
 *
 *  MT-Safe : YES!
 *
 ******************************************************************/

EXPORT_FUNC TT_Error TT_Copy_Outline(TT_Outline * source, TT_Outline * target)
{
	if (!source || !target || source->n_points != target->n_points || source->n_contours != target->n_contours)
		return TT_Err_Invalid_Argument;

	MEM_Copy(target->points, source->points, source->n_points * 2 * sizeof(TT_F26Dot6));

	MEM_Copy(target->flags, source->flags, source->n_points * sizeof(Byte));

	MEM_Copy(target->contours, source->contours, source->n_contours * sizeof(Short));

	target->high_precision = source->high_precision;
	target->second_pass = target->second_pass;
	target->dropout_mode = source->dropout_mode;

	return TT_Err_Ok;
}

/*******************************************************************
 *
 *  Function    :  TT_Transform_Outline
 *
 *  Description :  Applies a simple transformation to an outline.
 *
 *  Input  :  outline     the glyph's outline.  Can be extracted
 *                        from a glyph container through
 *                        TT_Get_Glyph_Outline().
 *
 *            matrix      simple matrix with 16.16 fixed floats
 *
 *  Output :  Error code (always TT_Err_Ok).
 *
 *  MT-Safe : YES!
 *
 ******************************************************************/

EXPORT_FUNC void TT_Transform_Outline(TT_Outline * outline, TT_Matrix * matrix)
{
	UShort n;
	TT_F26Dot6 x, y;
	TT_Vector *vec;

	vec = outline->points;
	for (n = 0; n < outline->n_points; n++) {
		x = TT_MulFix(vec->x, matrix->xx) + TT_MulFix(vec->y, matrix->xy);

		y = TT_MulFix(vec->x, matrix->yx) + TT_MulFix(vec->y, matrix->yy);

		vec->x = x;
		vec->y = y;
		vec++;
	}
}

/*******************************************************************
 *
 *  Function    :  TT_Transform_Vector
 *
 *  Description :  Apply a simple transform to a vector
 *
 *  Input  :  x, y        the vector.
 *
 *            matrix      simple matrix with 16.16 fixed floats
 *
 *  Output :  None.
 *
 *  MT-Safe : YES!
 *
 ******************************************************************/

EXPORT_FUNC void TT_Transform_Vector(TT_F26Dot6 * x, TT_F26Dot6 * y, TT_Matrix * matrix)
{
	TT_F26Dot6 xz, yz;

	xz = TT_MulFix(*x, matrix->xx) + TT_MulFix(*y, matrix->xy);

	yz = TT_MulFix(*x, matrix->yx) + TT_MulFix(*y, matrix->yy);

	*x = xz;
	*y = yz;
}

/*******************************************************************
 *
 *  Function    :  TT_Translate_Outline
 *
 *  Description :  Applies a simple translation.
 *
 *  Input  :  outline   no comment :)
 *            xOffset
 *            yOffset
 *
 *  Output :  Error code.
 *
 *  MT-Safe : YES!
 *
 ******************************************************************/

EXPORT_FUNC void TT_Translate_Outline(TT_Outline * outline, TT_F26Dot6 xOffset, TT_F26Dot6 yOffset)
{
	UShort n;
	TT_Vector *vec = outline->points;

	for (n = 0; n < outline->n_points; n++) {
		vec->x += xOffset;
		vec->y += yOffset;
		vec++;
	}
}

/*******************************************************************
 *
 *  Function    :  TT_Get_Outline_BBox
 *
 *  Description :  Returns an outline's bounding box.
 *
 *  Input  :  outline   no comment :)
 *            bbox      address where the bounding box is returned
 *
 *  Output :  Error code.
 *
 *  MT-Safe : YES!
 *
 ******************************************************************/

EXPORT_FUNC TT_Error TT_Get_Outline_BBox(TT_Outline * outline, TT_BBox * bbox)
{
	TT_F26Dot6 x, y;
	UShort k;

	if (outline && bbox) {
		if (outline->n_points == 0) {
			bbox->xMin = 0;
			bbox->yMin = 0;
			bbox->xMax = 0;
			bbox->yMax = 0;
		} else {
			TT_Vector *vec = outline->points;

			bbox->xMin = bbox->xMax = vec->x;
			bbox->yMin = bbox->yMax = vec->y;
			vec++;

			for (k = 1; k < outline->n_points; k++) {
				x = vec->x;
				if (x < bbox->xMin)
					bbox->xMin = x;
				if (x > bbox->xMax)
					bbox->xMax = x;
				y = vec->y;
				if (y < bbox->yMin)
					bbox->yMin = y;
				if (y > bbox->yMax)
					bbox->yMax = y;
				vec++;
			}
		}
		return TT_Err_Ok;
	} else
		return TT_Err_Invalid_Argument;
}

  /* ----------------- character mappings support ------------- */

/*******************************************************************
 *
 *  Function    :  TT_Get_CharMap_Count
 *
 *  Description :  Returns the number of charmaps in a given face.
 *
 *  Input  :  face   face object handle
 *
 *  Output :  Number of tables. -1 in case of error (bad handle).
 *
 *  Note   :  DON'T USE THIS FUNCTION! IT HAS BEEN DEPRECATED!
 *
 *            It is retained for backwards compatibility only and will
 *            fail on 16bit systems.
 *
 *  MT-Safe : YES !
 *
 ******************************************************************/

EXPORT_FUNC int TT_Get_CharMap_Count(TT_Face face)
{
	PFace faze = HANDLE_Face(face);

	return (faze ? faze->numCMaps : -1);
}

/*******************************************************************
 *
 *  Function    :  TT_Get_CharMap_ID
 *
 *  Description :  Returns the ID of a given charmap.
 *
 *  Input  :  face             face object handle
 *            charmapIndex     index of charmap in directory
 *            platformID       address of returned platform ID
 *            encodingID       address of returned encoding ID
 *
 *  Output :  error code
 *
 *  MT-Safe : YES !
 *
 ******************************************************************/

EXPORT_FUNC TT_Error TT_Get_CharMap_ID(TT_Face face, TT_UShort charmapIndex, TT_UShort * platformID,
									   TT_UShort * encodingID)
{
	PCMapTable cmap;
	PFace faze = HANDLE_Face(face);

	if (!faze)
		return TT_Err_Invalid_Face_Handle;

	if (charmapIndex >= faze->numCMaps)
		return TT_Err_Invalid_Argument;

	cmap = faze->cMaps + charmapIndex;

	*platformID = cmap->platformID;
	*encodingID = cmap->platformEncodingID;

	return TT_Err_Ok;
}

/*******************************************************************
 *
 *  Function    :  TT_Get_CharMap
 *
 *  Description :  Looks up a charmap.
 *
 *  Input  :  face          face object handle
 *            charmapIndex  index of charmap in directory
 *            charMap       address of returned charmap handle
 *
 *  Output :  Error code.
 *
 *  MT-Safe : YES!
 *
 ******************************************************************/

EXPORT_FUNC TT_Error TT_Get_CharMap(TT_Face face, TT_UShort charmapIndex, TT_CharMap * charMap)
{
	TT_Error error;
	TT_Stream stream;
	PCMapTable cmap;
	PFace faze = HANDLE_Face(face);

	if (!faze)
		return TT_Err_Invalid_Face_Handle;

	if (charmapIndex >= faze->numCMaps)
		return TT_Err_Invalid_Argument;

	cmap = faze->cMaps + charmapIndex;

	/* Load table if needed */
	error = TT_Err_Ok;

	/* MT-NOTE: We're modifying the face object, so protect it. */
	MUTEX_Lock(faze->lock);

	if (!cmap->loaded) {
		(void) USE_Stream(faze->stream, stream);
		if (!error) {
			error = CharMap_Load(cmap, stream);
			DONE_Stream(stream);
		}

		if (error)
			cmap = NULL;
		else
			cmap->loaded = TRUE;
	}
	MUTEX_Release(faze->lock);

	HANDLE_Set(*charMap, cmap);

	return error;
}

/*******************************************************************
 *
 *  Function    :  TT_Char_Index
 *
 *  Description :  Returns the glyph index corresponding to
 *                 a given character code defined for the 'charmap'.
 *
 *  Input  :  charMap    charmap handle
 *            charcode   character code
 *
 *  Output :  glyph index.
 *
 *  Notes  :  Character code 0 is the unknown glyph, which should never
 *            be displayed.
 *
 *  MT-Safe : YES!
 *
 ******************************************************************/

EXPORT_FUNC TT_UShort TT_Char_Index(TT_CharMap charMap, TT_UShort charCode)
{
	PCMapTable cmap = HANDLE_CharMap(charMap);

	if (!cmap)
		return 0;	/* we return 0 in case of invalid char map */

	return CharMap_Index(cmap, charCode);
}

/*******************************************************************
 *
 *  Function    :  TT_Get_Name_Count
 *
 *  Description :  Returns the number of strings found in the
 *                 name table.
 *
 *  Input  :  face   face handle
 *
 *  Output :  number of strings.
 *
 *  Notes  :  Returns -1 on error (invalid handle).
 *
 *            DON'T USE THIS FUNCTION! IT HAS BEEN DEPRECATED!
 *
 *            It is retained for backwards compatibility only and will
 *            fail on 16bit systems.
 *
 *  MT-Safe : YES!
 *
 ******************************************************************/

EXPORT_FUNC int TT_Get_Name_Count(TT_Face face)
{
	PFace faze = HANDLE_Face(face);

	if (!faze)
		return -1;

	return faze->nameTable.numNameRecords;
}

/*******************************************************************
 *
 *  Function    :  TT_Get_Name_ID
 *
 *  Description :  Returns the IDs of the string number 'nameIndex'
 *                 in the name table of a given face.
 *
 *  Input  :  face        face handle
 *            nameIndex   index of string. First is 0
 *            platformID  addresses of returned IDs
 *            encodingID
 *            languageID
 *            nameID
 *
 *  Output :  Error code.
 *
 *  Notes  :  Some files have a corrupt or unusual name table, with some
 *            entries having a platformID > 3.  These can usually
 *            be ignored by a client application.
 *
 *  MT-Safe : YES!
 *
 ******************************************************************/

EXPORT_FUNC TT_Error TT_Get_Name_ID(TT_Face face, TT_UShort nameIndex, TT_UShort * platformID, TT_UShort * encodingID,
									TT_UShort * languageID, TT_UShort * nameID)
{
	TNameRec *namerec;
	PFace faze = HANDLE_Face(face);

	if (!faze)
		return TT_Err_Invalid_Face_Handle;

	if (nameIndex >= faze->nameTable.numNameRecords)
		return TT_Err_Invalid_Argument;

	namerec = faze->nameTable.names + nameIndex;

	*platformID = namerec->platformID;
	*encodingID = namerec->encodingID;
	*languageID = namerec->languageID;
	*nameID = namerec->nameID;

	return TT_Err_Ok;
}

/*******************************************************************
 *
 *  Function    :  TT_Get_Name_String
 *
 *  Description :  Returns the address and length of a given
 *                 string found in the name table.
 *
 *  Input  :  face        face handle
 *            nameIndex   string index
 *            stringPtr   address of returned pointer to string
 *            length      address of returned string length
 *
 *  Output :  Error code.
 *
 *  Notes  :  If the string's platformID is invalid,
 *            stringPtr is NULL, and length is 0.
 *
 *  MT-Safe : YES!
 *
 ******************************************************************/

EXPORT_FUNC TT_Error TT_Get_Name_String(TT_Face face, TT_UShort nameIndex, TT_String ** stringPtr, TT_UShort * length)
{
	TNameRec *namerec;
	PFace faze = HANDLE_Face(face);

	if (!faze)
		return TT_Err_Invalid_Face_Handle;

	if (nameIndex >= faze->nameTable.numNameRecords)
		return TT_Err_Invalid_Argument;

	namerec = faze->nameTable.names + nameIndex;

	*stringPtr = (String *) namerec->string;
	*length = namerec->stringLength;

	return TT_Err_Ok;
}

/*******************************************************************
 *
 *  Function    :  TT_Get_Font_Data
 *
 *  Description :  Loads any font table into client memory.
 *
 *  Input  :  face     Face object to look for.
 *
 *            tag      Tag of table to load.  Use the value 0 if you
 *                     want to access the whole font file, else set
 *                     this parameter to a valid TrueType table tag
 *                     that you can forge with the MAKE_TT_TAG
 *                     macro.
 *
 *            offset   Starting offset in the table (or the file
 *                     if tag == 0).
 *
 *            buffer   Address of target buffer
 *
 *            length   Address of decision variable:
 *
 *                       if length == NULL:
 *                             Load the whole table.  Returns an
 *                             error if 'offset' != 0.
 *
 *                       if *length == 0 :
 *                             Exit immediately, returning the
 *                             length of the given table, or of
 *                             the font file, depending on the
 *                             value of 'tag'.
 *
 *                       if *length != 0 :
 *                             Load the next 'length' bytes of
 *                             table or font, starting at offset
 *                             'offset' (in table or font too).
 *
 *  Output :  Error code.
 *
 *  MT-Safe : YES!
 *
 ******************************************************************/

EXPORT_FUNC TT_Error TT_Get_Font_Data(TT_Face face, TT_ULong tag, TT_Long offset, void *buffer, TT_Long * length)
{
	PFace faze = HANDLE_Face(face);

	if (!faze)
		return TT_Err_Invalid_Face_Handle;

	return Load_TrueType_Any(faze, tag, offset, buffer, length);
}

  /************************ callback definition ******************/

  /* Register a new callback to the TrueType engine -- this should */
  /* only be used by higher-level libraries, not typical clients   */
  /*                                                               */
  /* This is not part of the current FreeType release, thus        */
  /* undefined...                                                  */

#if 0
EXPORT_FUNC TT_Error TT_Register_Callback(TT_Engine engine, int callback_id, void *callback_ptr)
{
	PEngine_Instance eng = HANDLE_Engine(engine);

	if (!eng)
		return TT_Err_Invalid_Argument;

	/* currently, we only support one callback */
	if (callback_id != TT_Callback_Glyph_Outline_Load)
		return TT_Err_Invalid_Argument;

	eng->glCallback = (TT_Glyph_Loader_Callback) callback_ptr;
	return TT_Err_Ok;
}
#endif							/* 0 */

/* END */
